/*****************************************************************************
 *   Copyright (C) 2008 John Schember <john@nachtimwald.com>                 *
 *                                                                           *
 *   This file is part of niwbillmanager.                                    *
 *                                                                           *
 *   niwbillmanager is free software: you can redistribute it and/or         *
 *   modify it under the terms of the GNU General Public License as          *
 *   published by the Free Software Foundation, either version 3 of the      *
 *   License, or (at your option) any later version.                         *
 *                                                                           *
 *   niwbillmanager is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of          *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the            *
 *   GNU General Public License for more details.                            *
 *                                                                           *
 *   You should have received a copy of the GNU General Public License       *
 *   along with niwbillmanager. If not, see                                  *
 *   <http://www.gnu.org/licenses/>.                                         *
 *****************************************************************************/

#ifndef BILLITEM_H
#define BILLITEM_H

#include <QDate>
#include <QSet>
#include <QSharedData>
#include <QSharedDataPointer>

class RecurringPeriodType
{
    public:
        enum RecurringPeriodTypes {
            NONE,
            MONTHLY,
            LASTDAYOFMONTH,
            YEARLY,
        };

        static QString recurringPeriodTypeToString(
            RecurringPeriodType::RecurringPeriodTypes recurringPeriodType);
        static RecurringPeriodType::RecurringPeriodTypes
            stringToRecurringPeriodType(QString type);
};

/**
 * Implicitly shared data associated with BillItem class.
 * @see BillItem
 */
class BillItemData : public QSharedData
{
    public:
        BillItemData();
        BillItemData(const BillItemData &other);
        ~BillItemData();

        double m_amountDue;
        bool m_autoPay;
        QDate *m_dateDue;
        QString *m_id;
        QString *m_payee;
        QString *m_paymentLocation;
        QString *m_paymentMethod;
        RecurringPeriodType::RecurringPeriodTypes m_paymentRecurringPeriod;
        bool m_paid;
        QString *m_name;
        QString *m_notes;
        QSet<QString> *m_tags;
};

/**
 * An object representing a bill.
 * Sets and accesses information associated with a bill. This is implicitly
 * shared.
 */
class BillItem
{
    public:
        BillItem();

        double getAmountDue() const;
        bool getAutoPay() const;
        QDate getDateDue() const;
        QString getId() const;
        QString getPayee() const;
        QString getPaymentLocation() const;
        QString getPaymentMethod() const;
        RecurringPeriodType::RecurringPeriodTypes getPaymentRecurringPeriod()
            const;
        bool getPaid() const;
        QString getName() const;
        QString getNotes() const;
        QSet<QString> getTags() const;

        void setAmountDue(double amountDue);
        void setAutoPay(bool autoPay);
        void setDateDue(const QDate &dateDue);
        void setId(const QString &id);
        void setPayee(const QString &payee);
        void setPaymentLocation(const QString &paymentLocation);
        void setPaymentMethod(const QString &paymentMethod);
        void setPaymentRecurringPeriod(
            RecurringPeriodType::RecurringPeriodTypes paymentRecurring);
        void setPaid(bool paid);
        void setName(const QString &name);
        void setNotes(const QString &notes);

        /**
         * Sets the tags associated with the bill item.
         * Replaces all tags with those in the given list.
         * @param tags A list of tags.
         */
        void setTags(const QSet<QString> &tags);
        void addTag(const QString &tag);
        void removeTag(const QString &tag);

        /**
        * Creates a space separated string from a string list.
        * @param stringList The string list.
        * @return A space separated string.
        */
        static QString stringSetToString(QSet<QString> stringSet);

    private:
        QSharedDataPointer<BillItemData> d;
};

// Following two inlines allow for BillItem to be used in QSet.
inline bool operator==(const BillItem &b1, const BillItem &b2)
{
    QSet<QString> b1Tags = b1.getTags();
    QSet<QString> b2Tags = b2.getTags();

    b1Tags.remove("");
    b2Tags.remove("");

    return b1.getAmountDue() == b2.getAmountDue()
        && b1.getAutoPay() == b2.getAutoPay()
        && b1.getDateDue() == b2.getDateDue()
        && b1.getId() == b2.getId()
        && b1.getPayee() == b2.getPayee()
        && b1.getPaymentLocation() == b2.getPaymentLocation()
        && b1.getPaymentMethod() == b2.getPaymentMethod()
        && b1.getPaymentRecurringPeriod() == b2.getPaymentRecurringPeriod()
        && b1.getPaid() == b2.getPaid()
        && b1.getName() == b2.getName()
        && b1.getNotes() == b2.getNotes()
        && b1Tags == b2Tags;
}

inline bool operator!=(const BillItem &b1, const BillItem &b2)
{
    return !(b1 == b2);
}

inline uint qHash(const BillItem &key)
{
    QString tags = "";
    Q_FOREACH (QString tag, key.getTags()) {
        tags += tag;
    }

    return qHash(QString::number(key.getAmountDue()))
        ^ qHash(key.getAutoPay())
        ^ qHash(key.getDateDue().toString(Qt::ISODate))
        ^ qHash(key.getId())
        ^ qHash(key.getPayee())
        ^ qHash(key.getPaymentLocation())
        ^ qHash(key.getPaymentMethod())
        ^ qHash(key.getPaymentRecurringPeriod())
        ^ qHash(key.getPaid())
        ^ qHash(key.getName())
        ^ qHash(key.getNotes())
        ^ qHash(tags);
}

#endif /* BILLITEM_H */
